﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Clandestine
{
    public delegate void ReachedDestinationDelegate(ParticleThing p);

    public class ParticleThing : Sprite
    {
        public Sprite[] Tail;
        public int tailLength = 10;
        public Point Destination;
        public float DestinationScale = 1f;
        public int DestinationSize = 0;
        private PointF exactPosition;
        private PointF ExactPosition
        {
            get { return exactPosition; }
            set 
            {
                exactPosition = value;
                this.Position = Point.Round(exactPosition);
            }
        }

        public float Speed = 4f;

        public float deltaScale = 0f;
        public float deltaX = 0f;
        public float deltaY = 0f;

        private int DestinationScaleTime;

        public event ReachedDestinationDelegate OnReachedDestination;
        public bool ReachedDestination = true;

        public ParticleThing(int size)
            : base("sphere.png")
        {
            this.Layer = 500;
            this.Superbright = true;

            // Scale
            DestinationScale = (float)size / (float)this.UnscaledWidth;
            DestinationSize = size;
            this.Scale = DestinationScale;
            this.Origin = new Point(this.Width / 2, this.Height / 2);

            // Setup tail
            Tail = new Sprite[tailLength];
            for (int i = 0; i < tailLength; i++)
            {
                Tail[i] = new Sprite("sphere.png");
                Tail[i].Color.A = ((float)i / (float)tailLength) * 1;
                Tail[i].Layer = this.Layer - (0.001f * i);
                Tail[i].Superbright = true;
            }
            scaleTail();

            Ticker.AddTimer(new DeltaMsTimedEvent(updateMovement));
        }

        public void SetPosition(Point p)
        {
            Position = p;
            updateTail();
        }

        private void scaleTail()
        {
            for (int i = 0; i < tailLength; i++)
            {
                Tail[i].Scale = ((float)0.20 + (float)(((float)i / (float)tailLength) * 0.80)) * this.Scale; 
                Tail[i].Origin = new Point(Tail[i].Width / 2, Tail[i].Height / 2);
            }
        }

        private void updateTail()
        {
            for (int i = 0; i < tailLength - 1; i++)
                Tail[i].Position = new Point(Tail[i + 1].X + ((Tail[i + 1].Width - Tail[i].Width) / 2), Tail[i + 1].Y + ((Tail[i + 1].Height - Tail[i].Height) / 2)); 
            Tail[tailLength - 1].Position = new Point(this.Position.X + ((this.Width - Tail[tailLength - 1].Width) / 2), this.Position.Y + ((this.Height - Tail[tailLength - 1].Height) / 2));
            scaleTail();
        }

        public void MoveTo(Point dest, int time)
        {
            Destination = dest;
            deltaX = (float)(dest.X - X) / (float)time;
            deltaY = (float)(dest.Y - Y) / (float)time;
            ReachedDestination = false;
        }


        public void GrowTo(int size, int time)
        {
            DestinationScaleTime = time;
            DestinationSize = size;
            DestinationScale = (float)DestinationSize / (float)this.UnscaledHeight;
            deltaScale = (float)(DestinationScale - Scale) / (float)DestinationScaleTime;
        }

        public void GrowBy(int size, int time)
        {
            DestinationSize += size;
            DestinationScaleTime += time;
            DestinationScale = (float)DestinationSize / (float)this.UnscaledHeight;
            deltaScale = (float)(DestinationScale - Scale) / (float)DestinationScaleTime;
        }

        public void updateMovement(float ms)
        {
            // Update Pos
            ExactPosition = new PointF(ExactPosition.X + (deltaX * ms), ExactPosition.Y + (deltaY*ms));

            // Where are we?
            if (Position.X >= (Destination.X * Math.Sign(deltaX)))
                deltaX = 0;
            if (Position.Y >= (Destination.Y * Math.Sign(deltaY)))
                deltaY = 0;
            if ((deltaX == 0) && (deltaY == 0) && !ReachedDestination)
            {
                ReachedDestination = true;
                if (OnReachedDestination != null)
                    OnReachedDestination(this);
            }

            // Update scale
            this.Scale += deltaScale * ms;
            DestinationScaleTime -= (int)ms;
            if (this.Scale >= (DestinationScale * Math.Sign(deltaScale)))
                deltaScale = 0f;

            updateTail();
        }

        public override void Dispose()
        {
            for (int i = 0; i < Tail.Length; i++)
                Tail[i].Dispose();
            base.Dispose();
        }

    }
}
